/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hu.rsc.feeds.server;

import hu.rsc.feeds.client.data.Category;
import hu.rsc.feeds.client.data.ColumnFilterInfo;
import hu.rsc.feeds.client.data.ColumnFilterList;
import hu.rsc.feeds.client.data.Dictionary;
import hu.rsc.feeds.client.data.Entry;
import hu.rsc.feeds.client.data.Feed;
import hu.rsc.feeds.client.data.FieldMapping;
import hu.rsc.feeds.client.data.GeneratedEntry;
import hu.rsc.feeds.client.data.GeneratedFeed;
import hu.rsc.feeds.client.data.InitData;
import hu.rsc.feeds.client.data.ServerMessage;
import hu.rsc.feeds.client.data.SystemFeed;
import hu.rsc.feeds.client.data.UserCategory;
import hu.rsc.feeds.client.data.UserFeed;
import hu.rsc.feeds.client.data.UserInfo;
import hu.rsc.feeds.client.service.RssReaderService;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpSession;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.Text;
import com.google.gwt.gen2.table.client.TableModelHelper;
import com.google.gwt.gen2.table.client.TableModelHelper.Request;
import com.google.gwt.gen2.table.client.TableModelHelper.Response;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * 
 * @author arbuckle
 */
public class RssReaderServiceImpl extends RemoteServiceServlet implements RssReaderService {
    private static final long serialVersionUID = 5787878979567074170L;
    public static final String TABLE_FEED = "Feed";
    public static final String TABLE_USER_FEED = "UserFeed";
    public static final String TABLE_USER = "User";
    public static final String TABLE_CATEGORY = "Category";
    public static final String TABLE_USER_CATEGORY = "UserCategory";
    public static final String TABLE_GENERATED_FEED = "GeneratedFeed";
    public static final String TABLE_GENERATED_ENTRY = "GeneratedEntry";
    public static final String TABLE_SYSTEM_FEED = "SystemFeed";

    //private HashMap<String, List<Entry>> entries = new HashMap<String, List<Entry>>();

    public static final String SENDER = "rscrssfeeds@gmail.com";//Arbuckle1
    public static final String APP_NAME = "Rsc Rssfeeds";

    private static final String APPLICATON_ALIAS = "rssfeeds";

    public static final SimpleDateFormat DATE_YEAR_MONTH_FORMAT = new SimpleDateFormat("yyyy-MM");

    public static final SimpleDateFormat DATE_POSTGRES_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    public static final String DEMO_LOGIN_HU = "Demo User";

    public static final String DEMO_LOGIN_EN = "Demo Felhasználó";

    public static final String DEMO_PASSWORD = "Demopassword11";

    public static final String DEMO_USERCATEGORY_EN_1 = "News";
    public static final String DEMO_USERCATEGORY_EN_2 = "Sports";
    public static final String DEMO_USERCATEGORY_EN_3 = "Fun";

    public static final String DEMO_USERCATEGORY_HU_1 = "Hírek";
    public static final String DEMO_USERCATEGORY_HU_2 = "Sport";
    public static final String DEMO_USERCATEGORY_HU_3 = "Humor";

    public static Date resetDateAfterMonth(Date date) {
	if (date == null) {
	    return null;
	}
	Date res = null;
	try {
	    res = DATE_POSTGRES_FORMAT.parse(DATE_YEAR_MONTH_FORMAT.format(date) + "-01");
	} catch (ParseException e) {
	    e.printStackTrace();
	}
	return res;
    }

    //Start a GAE BlobstoreService session and Objectify session
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

    private Cache cache;

    public RssReaderServiceImpl() {

    }

    @Override
    public InitData autenticate(String userName, String password) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_USER);
	query.addFilter(UserInfo.PROP_NAME, Query.FilterOperator.EQUAL, userName);
	query.addFilter(UserInfo.PROP_PASSWORD, Query.FilterOperator.EQUAL, password);

	UserInfo userInfo = null;

	if (userName == null && isLoggined()) {
	    userInfo = getLoginedUser();
	} else {
	    PreparedQuery pq = datastore.prepare(query);
	    for (Entity e : pq.asIterable()) {
		userInfo = new UserInfo();
		Long id = e.getKey().getId();
		String email = (String) e.getProperty(UserInfo.PROP_EMAIL);
		Long col = (Long) e.getProperty(UserInfo.PROP_COLS);
		Long row = (Long) e.getProperty(UserInfo.PROP_ROWS);
		String lang = (String) e.getProperty(UserInfo.PROP_LANG);
		Boolean needmail = e.getProperty(UserInfo.PROP_NEED_MAIL) != null ? (Boolean) e.getProperty(UserInfo.PROP_NEED_MAIL) : new Boolean(true);

		final HttpSession session = this.getThreadLocalRequest().getSession();
		userInfo.setId(id);
		userInfo.setUserName(userName);
		userInfo.setEmail(email);
		userInfo.setRows(row != null ? row : UserInfo.DEF_ROWS);
		userInfo.setCols(col != null ? col : UserInfo.DEF_COLS);
		userInfo.setLang(lang == null ? UserInfo.LANG_EN : lang);
		userInfo.setNeedmail(needmail);
		session.setAttribute("userInfo", userInfo);
	    }
	}
	InitData id = new InitData();
	id.setUsercategories(getUserCategories());
	id.setCategories(getCategories());
	id.setUserInfo(userInfo);
	return id;
    }

    @Override
    public InitData autenticateDemo(String language) {
	String userName = language.equals(UserInfo.LANG_EN) ? DEMO_LOGIN_EN : DEMO_LOGIN_HU;
	InitData id = autenticate(userName, DEMO_PASSWORD);
	if (id.getUserInfo() == null) {
	    createDemoData(language, false);
	}
	id = autenticate(userName, DEMO_PASSWORD);
	return id;
    }

    public void createDemoData(String language, boolean withoutSession) {
	String userName = language.equals(UserInfo.LANG_EN) ? DEMO_LOGIN_EN : DEMO_LOGIN_HU;
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_USER);
	query.addFilter(UserInfo.PROP_NAME, Query.FilterOperator.EQUAL, userName);
	query.addFilter(UserInfo.PROP_PASSWORD, Query.FilterOperator.EQUAL, DEMO_PASSWORD);

	//cleaning
	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable()) {
	    Long id = e.getKey().getId();
	    datastore.delete(e.getKey());

	    Query delQuery = new Query(TABLE_USER_FEED);
	    delQuery.addFilter(UserFeed.PROP_USER, Query.FilterOperator.EQUAL, id);
	    PreparedQuery dpq = datastore.prepare(query);
	    for (Entity de : dpq.asIterable()) {
		datastore.delete(de.getKey());
	    }

	    delQuery = new Query(TABLE_USER_CATEGORY);
	    delQuery.addFilter(UserCategory.PROP_USER, Query.FilterOperator.EQUAL, id);
	    dpq = datastore.prepare(query);
	    for (Entity de : dpq.asIterable()) {
		datastore.delete(de.getKey());
	    }

	    delQuery = new Query(TABLE_GENERATED_FEED);
	    delQuery.addFilter(GeneratedFeed.PROP_USERINFO, Query.FilterOperator.EQUAL, id);
	    dpq = datastore.prepare(query);
	    for (Entity de : dpq.asIterable()) {
		deleteGeneratedFeed(de.getKey().getId());
	    }

	    delQuery = new Query(TABLE_SYSTEM_FEED);
	    delQuery.addFilter(SystemFeed.PROP_USERINFO, Query.FilterOperator.EQUAL, id);
	    dpq = datastore.prepare(query);
	    for (Entity de : dpq.asIterable()) {
		deleteGeneratedSystemFeed(de.getKey().getId());
	    }
	}

	//create user
	Entity user = new Entity(TABLE_USER);
	user.setProperty(UserInfo.PROP_COLS, UserInfo.DEF_COLS);
	user.setProperty(UserInfo.PROP_EMAIL, "test@test.com");
	user.setProperty(UserInfo.PROP_LANG, language);
	user.setProperty(UserInfo.PROP_NAME, userName);
	user.setProperty(UserInfo.PROP_NEED_MAIL, new Boolean(false));
	user.setProperty(UserInfo.PROP_PASSWORD, DEMO_PASSWORD);
	user.setProperty(UserInfo.PROP_ROWS, UserInfo.DEF_ROWS);
	datastore.put(user);

	//create user_category
	List<Long> userCategories = new ArrayList<Long>();
	userCategories.add(null);
	Entity uc1 = new Entity(TABLE_USER_CATEGORY);
	uc1.setProperty(UserCategory.PROP_LABEL, language.equals(UserInfo.LANG_EN) ? DEMO_USERCATEGORY_EN_1 : DEMO_USERCATEGORY_HU_1);
	uc1.setProperty(UserCategory.PROP_USER, user.getKey().getId());
	datastore.put(uc1);

	Entity uc2 = new Entity(TABLE_USER_CATEGORY);
	uc2.setProperty(UserCategory.PROP_LABEL, language.equals(UserInfo.LANG_EN) ? DEMO_USERCATEGORY_EN_2 : DEMO_USERCATEGORY_HU_2);
	uc2.setProperty(UserCategory.PROP_USER, user.getKey().getId());
	datastore.put(uc2);

	Entity uc3 = new Entity(TABLE_USER_CATEGORY);
	uc3.setProperty(UserCategory.PROP_LABEL, language.equals(UserInfo.LANG_EN) ? DEMO_USERCATEGORY_EN_3 : DEMO_USERCATEGORY_HU_3);
	uc3.setProperty(UserCategory.PROP_USER, user.getKey().getId());
	datastore.put(uc3);

	userCategories.add(uc1.getKey().getId());
	userCategories.add(uc2.getKey().getId());
	userCategories.add(uc3.getKey().getId());

	List<UserFeed> feeds = getUserFeedsRandom(12, language, withoutSession);
	for (int r = 0; r < 4; r++) {
	    for (int c = 0; c < 3; c++) {
		try {
		    UserFeed feed = feeds.get(r * c);
		    Entity uf = new Entity(TABLE_USER_FEED);
		    uf.setProperty(UserFeed.PROP_CATEGORY, userCategories.get(r));
		    uf.setProperty(UserFeed.PROP_FEED, feed.getFeed());
		    uf.setProperty(UserFeed.PROP_OPENED, new Boolean(c % 2 == 1));
		    uf.setProperty(UserFeed.PROP_USER, user.getKey().getId());
		    uf.setProperty(UserFeed.PROP_X, new Integer(0).toString());
		    uf.setProperty(UserFeed.PROP_Y, new Integer(c).toString());
		    datastore.put(uf);
		} catch (Exception e) {

		}
	    }
	}

	//create generated_feed
	boolean isen = language.equals(UserInfo.LANG_EN);
	Entity gf = new Entity(TABLE_GENERATED_FEED);
	gf.setProperty(GeneratedFeed.PROP_AUTHOR, userName);
	gf.setProperty(GeneratedFeed.PROP_PUB_DATE, new Date());
	gf.setProperty(GeneratedFeed.PROP_TITLE, isen ? "Demo channel" : "Demo csatorna");
	gf.setProperty(GeneratedFeed.PROP_USERINFO, user.getKey().getId());
	datastore.put(gf);

	Entity ge = new Entity(TABLE_GENERATED_ENTRY);
	ge.setProperty(GeneratedEntry.PROP_DESC, new Text(isen ? "This is a demo entry, what can contain any <span style=\"color:red;\">HTML</span> code."
		: "Ez egy demo bejegyzés ami tartalmazhat bármilyen <span style=\"color:red;\">HTML</span> kódot."));
	ge.setProperty(GeneratedEntry.PROP_FEED, gf.getKey().getId());
	ge.setProperty(GeneratedEntry.PROP_LINK, "rscrssreader.appspot.com");
	ge.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	ge.setProperty(GeneratedEntry.PROP_TITLE, isen ? "HTML entries" : "HTML bejegyzések");
	datastore.put(ge);

	ge = new Entity(TABLE_GENERATED_ENTRY);
	ge.setProperty(GeneratedEntry.PROP_DESC, new Text(
		isen ? "You can use this own channel in outher rss reader apps, or you can offer and use this in this application."
			: "A saját csatornát használhatod külső rss olvasó programokban, vagy akár ajánlhatod és használhatod ebben az alkalmazásban."));
	ge.setProperty(GeneratedEntry.PROP_FEED, gf.getKey().getId());
	ge.setProperty(GeneratedEntry.PROP_LINK, "rscrssreader.appspot.com");
	ge.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	ge.setProperty(GeneratedEntry.PROP_TITLE, isen ? "Use it" : "Használd");
	datastore.put(ge);

	//create system_feeds
	Entity sf = new Entity(TABLE_SYSTEM_FEED);
	sf.setProperty(SystemFeed.PROP_APPLICATION, "demoapp");
	sf.setProperty(SystemFeed.PROP_AUTHOR, userName);
	sf.setProperty(SystemFeed.PROP_ISHELP, new Boolean(true));
	sf.setProperty(SystemFeed.PROP_LANGUAGE, language);
	sf.setProperty(SystemFeed.PROP_USERINFO, user.getKey().getId());
	datastore.put(sf);

	ge = new Entity(TABLE_GENERATED_ENTRY);
	ge.setProperty(GeneratedEntry.PROP_DESC, new Text(isen ? "You can use this help within any your apps."
		: "Ezt a súgót, bármely saját alkalmazásodban tudod használni."));
	ge.setProperty(GeneratedEntry.PROP_FEED, sf.getKey().getId());
	ge.setProperty(GeneratedEntry.PROP_LINK, "rscrssreader.appspot.com");
	ge.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	ge.setProperty(GeneratedEntry.PROP_TITLE, isen ? "Use it" : "Használd");
	datastore.put(ge);

	ge = new Entity(TABLE_GENERATED_ENTRY);
	ge.setProperty(GeneratedEntry.PROP_DESC, new Text(isen ? "You can use any HTML format:<br/><ul><li>paragraphs</li><li>fonts</li><li>styles</li></ul>"
		: "Bármilyen HTML formázást használhatsz:<br/><ul><li>bekezdések</li><li>betűtípusok</li><li>stílusok</li></ul>."));
	ge.setProperty(GeneratedEntry.PROP_FEED, sf.getKey().getId());
	ge.setProperty(GeneratedEntry.PROP_LINK, "rscrssreader.appspot.com");
	ge.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	ge.setProperty(GeneratedEntry.PROP_TITLE, isen ? "Custom format" : "Egyedi formátum");
	datastore.put(ge);

	ge = new Entity(TABLE_GENERATED_ENTRY);
	ge.setProperty(GeneratedEntry.PROP_DESC, new Text(
		isen ? "Each entry has an own URL, what deffine it. If you call this URL only the selected entry will be published."
			: "Minden bejegyzés egyedi URL címezhető. Ha az egyedi címet hívod meg, csak a kiválasztott bejegyzés lesz publikálva."));
	ge.setProperty(GeneratedEntry.PROP_FEED, sf.getKey().getId());
	ge.setProperty(GeneratedEntry.PROP_LINK, "rscrssreader.appspot.com");
	ge.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	ge.setProperty(GeneratedEntry.PROP_TITLE, isen ? "Context sensitive" : "Környezet érzékeny");
	datastore.put(ge);

    }

    @Override
    public String deleteGeneratedEntry(Long id) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	try {
	    Key key = KeyFactory.createKey(TABLE_GENERATED_ENTRY, id);
	    datastore.delete(key);
	    return null;
	} catch (Exception e) {
	    return Dictionary.MESSAGE_DELETE_ERROR;
	}
    }

    @Override
    public String deleteGeneratedFeed(Long id) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	try {
	    Key key = KeyFactory.createKey(TABLE_GENERATED_FEED, id);

	    final Query query = new Query(TABLE_GENERATED_ENTRY);
	    query.addFilter(GeneratedEntry.PROP_FEED, Query.FilterOperator.EQUAL, id);

	    PreparedQuery pq = datastore.prepare(query);
	    for (Entity e : pq.asIterable()) {
		datastore.delete(e.getKey());
	    }

	    datastore.delete(key);
	    return null;
	} catch (Exception e) {
	    return Dictionary.MESSAGE_DELETE_ERROR;
	}
    }

    @Override
    public String deleteGeneratedSystemFeed(Long id) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	try {
	    Key key = KeyFactory.createKey(TABLE_SYSTEM_FEED, id);

	    final Query query = new Query(TABLE_GENERATED_ENTRY);
	    query.addFilter(GeneratedEntry.PROP_FEED, Query.FilterOperator.EQUAL, id);

	    PreparedQuery pq = datastore.prepare(query);
	    for (Entity e : pq.asIterable()) {
		datastore.delete(e.getKey());
	    }

	    datastore.delete(key);
	    return null;
	} catch (Exception e) {
	    return Dictionary.MESSAGE_DELETE_ERROR;
	}
    }

    @Override
    public void deleteUserFeed(UserFeed userFeed) {
	if (userFeed != null && userFeed.getId() != null) {
	    final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	    Key key = KeyFactory.createKey(TABLE_USER_FEED, userFeed.getId());
	    datastore.delete(key);
	}
    }

    @Override
    public InitData doInit() {
	InitData id = new InitData();
	//getFeedsPrivate();

	id.setCategories(getCategories());
	id.setUsercategories(getUserCategories());
	return id;
    }

    @Override
    public String getBlobStoreUploadUrl() {
	return this.blobstoreService.createUploadUrl("/blobstoreexample/uploadservice");
    }

    @Override
    public List<Category> getCategories() {
	List<Category> categories = new ArrayList<Category>();
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	final Query query = new Query(TABLE_CATEGORY);
	PreparedQuery pq = datastore.prepare(query);
	for (Entity c : pq.asIterable()) {
	    Long id = c.getKey().getId();
	    String title = (String) c.getProperty(Category.PROP_LABEL);
	    String lang = (String) c.getProperty(Category.PROP_LANGUAGE);
	    if (lang == null) {
		lang = UserInfo.LANG_EN;
	    }
	    Category cat = new Category();
	    cat.setId(id);
	    cat.setLabel(title);
	    cat.setLanguage(lang);
	    categories.add(cat);
	}
	return categories;
    }

    @Override
    public Entry[] getEntries(String key) {
	Feed feed = null;
	if (this.cache != null) {
	    feed = (Feed) this.cache.get(key);
	}
	if (feed == null) {
	    HashMap<String, Feed> feeds = getFeedsPrivate(key);
	    feed = feeds.get(key);
	}
	String url = feed.getUrl();
	RssFeedParser rfp;
	List<Entry> entries = new ArrayList<Entry>();
	try {
	    rfp = new RssFeedParser(url, key);
	    entries = rfp.getPostings();
	} catch (Exception e) {
	    e.printStackTrace();
	}

	Entry[] result = new Entry[entries.size()];
	entries.toArray(result);
	return result;
    }

    @Override
    public List<Feed> getFeeds() {
	HashMap<String, Feed> feeds = getFeedsPrivate(null);
	List<Feed> answer = new ArrayList<Feed>();
	answer.addAll(feeds.values());
	return answer;
    }

    @Override
    public Response<Feed> getFeeds(Request request) {
	int startRow = request.getStartRow();
	int numRows = request.getNumRows();

	return new TableModelHelper.SerializableResponse<Feed>(getFeeds(request.getColumnSortList().getPrimaryColumn(), request.getColumnSortList()
		.getPrimaryColumnSortInfo().isAscending(), startRow, numRows));
    }

    @Override
    public int getFeedsCount(ColumnFilterList filters) {
	return getFeeds(FieldMapping.FIELD_GEN_FEED_ID, true, 0, Integer.MAX_VALUE).size();
    }

    @Override
    public Response<GeneratedEntry> getGeneratedEntries(Request request, ColumnFilterList filters, Long generatedFeed) {
	int startRow = request.getStartRow();
	int numRows = request.getNumRows();
	return new TableModelHelper.SerializableResponse<GeneratedEntry>(getGeneratedEntries(request.getColumnSortList().getPrimaryColumn(), request
		.getColumnSortList().getPrimaryColumnSortInfo().isAscending(), filters, generatedFeed, startRow, numRows));
    }

    @Override
    public int getGeneratedEntriesCount(ColumnFilterList filters, Long generatedFeed) {
	return getGeneratedEntries(FieldMapping.FIELD_ENTRY_ID, true, filters, generatedFeed, 0, Integer.MAX_VALUE).size();
    }

    @Override
    public Response<GeneratedFeed> getGeneratedFeeds(Request request) {
	int startRow = request.getStartRow();
	int numRows = request.getNumRows();

	return new TableModelHelper.SerializableResponse<GeneratedFeed>(getGeneratedFeeds(request.getColumnSortList().getPrimaryColumn(), request
		.getColumnSortList().getPrimaryColumnSortInfo().isAscending(), startRow, numRows));
    }

    @Override
    public Integer getGeneratedFeedsCount(ColumnFilterList filters) {
	return getGeneratedFeeds(FieldMapping.FIELD_GEN_FEED_ID, true, 0, Integer.MAX_VALUE).size();
    }

    @Override
    public Response<SystemFeed> getSystemFeeds(Request request) {
	int startRow = request.getStartRow();
	int numRows = request.getNumRows();

	return new TableModelHelper.SerializableResponse<SystemFeed>(getSystemFeeds(request.getColumnSortList().getPrimaryColumn(), request.getColumnSortList()
		.getPrimaryColumnSortInfo().isAscending(), startRow, numRows));
    }

    @Override
    public int getSystemFeedsCount(ColumnFilterList filters) {
	return getSystemFeeds(FieldMapping.FIELD_GEN_FEED_ID, true, 0, Integer.MAX_VALUE).size();
    }

    @Override
    public List<UserFeed> getUserFeeds() {
	//deleteAllUserFeeds();

	List<UserFeed> result = new ArrayList<UserFeed>();
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	//this.rssFeeds.clear();

	if (isLoggined()) {
	    final Query query = new Query(TABLE_USER_FEED);
	    query.addFilter(UserFeed.PROP_USER, Query.FilterOperator.EQUAL, getLoginedUser().getId());

	    PreparedQuery pq = datastore.prepare(query);
	    for (Entity e : pq.asIterable()) {
		Long id = e.getKey().getId();
		String x = (String) e.getProperty(UserFeed.PROP_X);
		String y = (String) e.getProperty(UserFeed.PROP_Y);
		Long category = (Long) e.getProperty(UserFeed.PROP_FEED);
		Long user = (Long) e.getProperty(UserFeed.PROP_USER);
		Long usercategory = (Long) e.getProperty(UserFeed.PROP_CATEGORY);
		Boolean opened = (Boolean) e.getProperty(UserFeed.PROP_OPENED);
		UserFeed c = new UserFeed();
		c.setId(id);
		c.setX(Integer.parseInt(x));
		c.setY(Integer.parseInt(y));
		c.setFeed(category);
		c.setUser(user);
		c.setUsercategory(usercategory);
		c.setOpened(opened != null ? opened : new Boolean(false));
		result.add(c);
	    }
	} else {
	    /*final Query query = new Query(TABLE_FEED);
	    query.addSort(Feed.PROP_OFFER_DATE, SortDirection.DESCENDING);
	    PreparedQuery pq = datastore.prepare(query);
	    int i = 0;
	    for (Entity e : pq.asIterable(FetchOptions.Builder.withLimit(9))) {
	    Long id = e.getKey().getId();

	    UserFeed c = new UserFeed();
	    c.setId(id);
	    c.setY(i % 3);
	    c.setX(i / 3);
	    c.setFeed(e.getKey().getId());
	    c.setUser(getLoginedUser() != null ? getLoginedUser().getId() : null);
	    c.setUsercategory(null);
	    c.setOpened(false);
	    result.add(c);
	    i++;
	    }*/
	    String language = getLoginedUser().getLang() != null && getLoginedUser().getLang().equals(UserInfo.LANG_HU) ? UserInfo.LANG_HU : UserInfo.LANG_EN;
	    result = getUserFeedsRandom(9, language, false);
	}

	return result;
    }

    public List<UserFeed> getUserFeedsRandom(int count, String language, boolean withoutSession) {
	List<UserFeed> result = new ArrayList<UserFeed>();
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_FEED);
	query.addFilter(Feed.PROP_LANGUAGE, Query.FilterOperator.EQUAL, language);
	query.addSort(Feed.PROP_OFFER_DATE, SortDirection.DESCENDING);
	PreparedQuery pq = datastore.prepare(query);
	int i = 0;
	for (Entity e : pq.asIterable(FetchOptions.Builder.withLimit(count))) {
	    Long id = e.getKey().getId();

	    UserFeed c = new UserFeed();
	    c.setId(id);
	    c.setY(i % 3);
	    c.setX(i / 3);
	    c.setFeed(e.getKey().getId());
	    c.setUser(!withoutSession && getLoginedUser() != null ? getLoginedUser().getId() : null);
	    c.setUsercategory(null);
	    c.setOpened(false);
	    result.add(c);
	    i++;
	}
	return result;
    }

    @Override
    public Boolean isLoggined() {
	UserInfo ui = getLoginedUser();
	return ui != null && ui.getId() != null && ui.getId() > 1l;
    }

    @Override
    public InitData logout() {
	final HttpSession session = this.getThreadLocalRequest().getSession();
	session.invalidate();
	InitData id = new InitData();
	id.setCategories(getCategories());
	id.setUsercategories(getUserCategories());
	return id;
    }

    @Override
    public Category newCategory(Category category) {
	if (category == null || category.getLabel() == null || category.getLabel().length() == 0) {
	    return null;
	}
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_CATEGORY);
	query.addFilter(Category.PROP_LABEL, Query.FilterOperator.EQUAL, category.getLabel());

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable()) {
	    return null;
	}

	Entity e = new Entity(TABLE_CATEGORY);
	e.setProperty(Category.PROP_LABEL, category.getLabel());
	e.setProperty(Category.PROP_LANGUAGE, category.getLanguage());
	datastore.put(e);

	category.setId(e.getKey().getId());

	return category;
    }

    @Override
    public UserCategory newUserCategory(UserCategory usercategory) {
	if (usercategory == null || usercategory.getLabel() == null || usercategory.getLabel().length() == 0) {
	    return null;
	}
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_USER_CATEGORY);
	query.addFilter(UserCategory.PROP_LABEL, Query.FilterOperator.EQUAL, usercategory.getLabel());

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable()) {
	    return null;
	}

	Entity e = new Entity(TABLE_USER_CATEGORY);
	e.setProperty(UserCategory.PROP_LABEL, usercategory.getLabel());
	e.setProperty(UserCategory.PROP_USER, getLoginedUser().getId());
	datastore.put(e);

	usercategory.setId(e.getKey().getId());

	return usercategory;
    }

    @Override
    public Feed offer(String name, String url, Long category, String language, String description) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	Query query = new Query(TABLE_FEED);
	query.addFilter(Feed.PROP_URL, Query.FilterOperator.EQUAL, url);

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable()) {
	    return null;
	}
	try {
	    boolean valid = checkChanelUrl(url);
	    if (valid) {
		Entity e = new Entity(TABLE_FEED);
		e.setProperty(Feed.PROP_LABEL, name);
		e.setProperty(Feed.PROP_URL, url);
		e.setProperty(Feed.PROP_CATEGORY, category);
		e.setProperty(Feed.PROP_LANGUAGE, language);
		e.setProperty(Feed.PROP_DESCRIPTION, description);
		e.setProperty(Feed.PROP_OFFER_DATE, new Date());
		e.setProperty(Feed.PROP_OFFER_OFFERER, getLoginedUser().getId());
		datastore.put(e);

		/**
		 * Save a news entry with the data of the offered chanel.
		 */
		try {
		    query = new Query(RssReaderServiceImpl.TABLE_SYSTEM_FEED);
		    query.addFilter(SystemFeed.PROP_APPLICATION, Query.FilterOperator.EQUAL, APPLICATON_ALIAS);
		    query.addFilter(SystemFeed.PROP_ISHELP, Query.FilterOperator.EQUAL, new Boolean(false));
		    String lang = language;
		    if (lang != null && lang.length() > 0) {
			query.addFilter(SystemFeed.PROP_LANGUAGE, Query.FilterOperator.EQUAL, lang);
		    }
		    pq = datastore.prepare(query);

		    Long systemFeedId = null;

		    for (Entity se : pq.asIterable()) {
			systemFeedId = se.getKey().getId();
		    }
		    if (systemFeedId != null) {
			GeneratedEntry news = new GeneratedEntry();
			news.setFeed(systemFeedId);
			news.setPubdate(new Date());
			if (lang != null && lang.equals(UserInfo.LANG_HU)) {
			    news.setTitle("Új csatorna: " + name);
			    StringBuilder sb = new StringBuilder();
			    sb.append(getLoginedUser().getUserName());
			    sb.append(" ajánlott egy új csatornát: ").append(name).append(".<br/>");
			    sb.append("Leírás: <br/>").append(description);
			    news.setDescription(sb.toString());
			} else {
			    news.setTitle("New channel: " + name);
			    StringBuilder sb = new StringBuilder();
			    sb.append(getLoginedUser().getUserName());
			    sb.append(" offered a new channel: ").append(name).append(".<br/>");
			    sb.append("Description: <br/>").append(description);
			    news.setDescription(sb.toString());
			}
			saveGeneratedEntry(news);
			sendMailForNewFeed(news, lang);

		    }
		} catch (Exception ex) {
		    ex.printStackTrace();
		}

		HashMap<String, Feed> feeds = getFeedsPrivate(null);
		for (String key : feeds.keySet()) {
		    if (key.equals(name)) {
			return feeds.get(key);
		    }
		}
	    }
	} catch (Exception e) {
	    return null;
	}
	return null;
    }

    @Override
    public InitData register(UserInfo userInfo) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_USER);
	query.addFilter(UserInfo.PROP_NAME, Query.FilterOperator.EQUAL, userInfo.getUserName());

	PreparedQuery pq = datastore.prepare(query);
	int count = 0;
	for (Entity result : pq.asIterable()) {
	    Long id = result.getKey().getId();
	    if (userInfo.getId() != null && userInfo.getId() > 0 && userInfo.getId().equals(id)) {
		continue;
	    }
	    count++;
	}
	boolean hasSameName = count != 0;

	if (hasSameName) {
	    return null;
	}
	Entity user = null;
	if (userInfo.getId() != null && userInfo.getId() > 0) {
	    Key key = KeyFactory.createKey(TABLE_USER, userInfo.getId());
	    try {
		user = datastore.get(key);
	    } catch (EntityNotFoundException e) {
		return null;
	    }
	} else {
	    user = new Entity(TABLE_USER);
	}
	user.setProperty(UserInfo.PROP_EMAIL, userInfo.getEmail());
	/**
	 * The demo user's name and password can not be changed.
	 */
	boolean isdemo = userInfo.getUserName().equals(DEMO_LOGIN_EN) || userInfo.getUserName().equals(DEMO_LOGIN_HU);
	if (!isdemo) {
	    user.setProperty(UserInfo.PROP_NAME, userInfo.getUserName());
	}
	if (!isdemo && userInfo.getId() != null && userInfo.getId() > 0 && userInfo.getPassword() != null && userInfo.getPassword().length() > 0) {
	    user.setProperty(UserInfo.PROP_PASSWORD, userInfo.getPassword());
	} else if (userInfo.getId() == null || userInfo.getId() < 0) {
	    user.setProperty(UserInfo.PROP_PASSWORD, userInfo.getPassword());
	}
	user.setProperty(UserInfo.PROP_ROWS, userInfo.getRows());
	user.setProperty(UserInfo.PROP_COLS, userInfo.getCols());
	user.setProperty(UserInfo.PROP_LANG, userInfo.getLang());
	user.setProperty(UserInfo.PROP_NEED_MAIL, userInfo.getNeedmail() != null ? userInfo.getNeedmail() : new Boolean(false));

	datastore.put(user);

	final HttpSession session = this.getThreadLocalRequest().getSession(true);
	if (userInfo.getId() != null && userInfo.getId() > 0) {
	    session.setAttribute("userInfo", userInfo);
	    userInfo.setPassword(null);
	} else {
	    autenticate(userInfo.getUserName(), userInfo.getPassword());
	    userInfo = (UserInfo) session.getAttribute("userInfo");
	}
	InitData id = new InitData();
	id.setCategories(getCategories());
	id.setUsercategories(getUserCategories());
	id.setUserInfo(userInfo);
	return id;
    }

    @Override
    public Feed saveFeed(Feed feed) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	Entity f = null;
	if (feed.getId() != null && feed.getId() > 0l) {
	    Key key = KeyFactory.createKey(TABLE_FEED, feed.getId());
	    try {
		f = datastore.get(key);
	    } catch (EntityNotFoundException e) {
	    }

	} else {
	    return offer(feed.getLabel(), feed.getUrl(), feed.getCategory(), feed.getLanguage(), feed.getDescription());
	}

	if (feed.getOfferer() == null) {
	    f.setProperty(Feed.PROP_OFFER_OFFERER, getLoginedUser().getId());
	}
	f.setProperty(Feed.PROP_CATEGORY, feed.getCategory());
	f.setProperty(Feed.PROP_DESCRIPTION, feed.getDescription());
	f.setProperty(Feed.PROP_LABEL, feed.getLabel());
	f.setProperty(Feed.PROP_LANGUAGE, feed.getLanguage());

	datastore.put(f);
	feed.setId(f.getKey().getId());
	return feed;
    }

    @Override
    public GeneratedEntry saveGeneratedEntry(GeneratedEntry entry) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	Entity f = null;
	if (entry.getId() != null && entry.getId() > 0l) {
	    Key key = KeyFactory.createKey(TABLE_GENERATED_ENTRY, entry.getId());
	    try {
		f = datastore.get(key);
	    } catch (EntityNotFoundException e) {
	    }

	} else {
	    f = new Entity(TABLE_GENERATED_ENTRY);
	    f.setProperty(GeneratedEntry.PROP_PUB_DATE, new Date());
	}

	f.setProperty(GeneratedEntry.PROP_DESC, new Text(entry.getDescription()));
	f.setProperty(GeneratedEntry.PROP_FEED, entry.getFeed());
	f.setProperty(GeneratedEntry.PROP_LINK, entry.getLink());
	f.setProperty(GeneratedEntry.PROP_TITLE, entry.getTitle());

	datastore.put(f);
	entry.setId(f.getKey().getId());
	return entry;
    }

    @Override
    public GeneratedFeed saveGeneratedFeed(GeneratedFeed feed) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	Entity f = null;
	if (feed.getId() != null && feed.getId() > 0l) {
	    Key key = KeyFactory.createKey(TABLE_GENERATED_FEED, feed.getId());
	    try {
		f = datastore.get(key);
	    } catch (EntityNotFoundException e) {
	    }

	} else {
	    f = new Entity(TABLE_GENERATED_FEED);
	}

	f.setProperty(GeneratedFeed.PROP_AUTHOR, feed.getAuthor());
	f.setProperty(GeneratedFeed.PROP_PUB_DATE, feed.getPubDate());
	f.setProperty(GeneratedFeed.PROP_TITLE, feed.getTitle());
	f.setProperty(GeneratedFeed.PROP_USERINFO, getLoginedUser().getId());

	datastore.put(f);
	feed.setId(f.getKey().getId());
	return feed;
    }

    @Override
    public ServerMessage<SystemFeed> saveSystemFeed(SystemFeed feed) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	Entity f = null;

	final Query sameQuery = new Query(TABLE_SYSTEM_FEED);
	sameQuery.addFilter(SystemFeed.PROP_APPLICATION, Query.FilterOperator.EQUAL, feed.getApplication());
	sameQuery.addFilter(SystemFeed.PROP_USERINFO, Query.FilterOperator.NOT_EQUAL, getLoginedUser().getId());
	PreparedQuery pq = datastore.prepare(sameQuery);
	HashMap<String, Long> apps = new HashMap<String, Long>();
	for (Entity result : pq.asIterable()) {
	    apps.put((String) result.getProperty(SystemFeed.PROP_APPLICATION), result.getKey().getId());
	}

	final Query typeQuery = new Query(TABLE_SYSTEM_FEED);
	typeQuery.addFilter(SystemFeed.PROP_APPLICATION, Query.FilterOperator.EQUAL, feed.getApplication());
	typeQuery.addFilter(SystemFeed.PROP_ISHELP, Query.FilterOperator.EQUAL, feed.getHelp());
	typeQuery.addFilter(SystemFeed.PROP_LANGUAGE, Query.FilterOperator.EQUAL, feed.getLanguage());
	pq = datastore.prepare(typeQuery);
	int typecount = 0;
	for (Entity result : pq.asIterable()) {
	    typecount++;
	}

	if (feed.getId() != null && feed.getId() > 0l) {
	    Key key = KeyFactory.createKey(TABLE_SYSTEM_FEED, feed.getId());
	    if (apps.size() > 1) {
		ServerMessage<SystemFeed> sm = new ServerMessage<SystemFeed>();
		sm.setMessage(Dictionary.MESSAGE_SAME_APP);
		sm.setObject(feed);
		sm.setSuccess(false);
		return sm;
	    }
	    if (typecount > 1) {
		ServerMessage<SystemFeed> sm = new ServerMessage<SystemFeed>();
		sm.setMessage(Dictionary.MESSAGE_HAS_TYPE);
		sm.setObject(feed);
		sm.setSuccess(false);
		return sm;
	    }
	    try {
		f = datastore.get(key);
	    } catch (EntityNotFoundException e) {
	    }

	} else {
	    if (apps.size() > 0) {
		ServerMessage<SystemFeed> sm = new ServerMessage<SystemFeed>();
		sm.setMessage(Dictionary.MESSAGE_SAME_APP);
		sm.setObject(feed);
		sm.setSuccess(false);
	    }
	    if (typecount > 0) {
		ServerMessage<SystemFeed> sm = new ServerMessage<SystemFeed>();
		sm.setMessage(Dictionary.MESSAGE_HAS_TYPE);
		sm.setObject(feed);
		sm.setSuccess(false);
		return sm;
	    }
	    f = new Entity(TABLE_SYSTEM_FEED);
	}

	f.setProperty(SystemFeed.PROP_AUTHOR, getLoginedUser().getUserName());
	f.setProperty(SystemFeed.PROP_APPLICATION, feed.getApplication());
	f.setProperty(SystemFeed.PROP_ISHELP, feed.getHelp() != null ? feed.getHelp() : new Boolean(false));
	f.setProperty(SystemFeed.PROP_USERINFO, getLoginedUser().getId());
	f.setProperty(SystemFeed.PROP_LANGUAGE, feed.getLanguage());

	datastore.put(f);
	feed.setId(f.getKey().getId());
	ServerMessage<SystemFeed> sm = new ServerMessage<SystemFeed>();
	sm.setObject(feed);
	sm.setSuccess(true);
	return sm;
    }

    @Override
    public String saveUserFeeds(List<UserFeed> l) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	for (UserFeed uc : l) {
	    Entity f = null;
	    if (uc.getId() != null && uc.getId() > 0l) {
		Key key = KeyFactory.createKey(TABLE_USER_FEED, uc.getId());
		try {
		    f = datastore.get(key);
		} catch (EntityNotFoundException e) {
		    continue;
		}

	    } else {
		f = new Entity(TABLE_USER_FEED);
	    }

	    f.setProperty(UserFeed.PROP_USER, uc.getUser() != null ? uc.getUser() : getLoginedUser().getId());
	    f.setProperty(UserFeed.PROP_FEED, uc.getFeed());
	    f.setProperty(UserFeed.PROP_X, uc.getX().toString());
	    f.setProperty(UserFeed.PROP_Y, uc.getY().toString());
	    f.setProperty(UserFeed.PROP_CATEGORY, uc.getUsercategory());
	    f.setProperty(UserFeed.PROP_OPENED, uc.getOpened() != null ? uc.getOpened() : new Boolean(false));

	    datastore.put(f);

	}
	return "ok";
    }

    @Override
    public void sendPost(Entry entry, List<String> recipients) {
	if (recipients.isEmpty()) {
	    return;
	}

	new ShareEntry(entry, getLoginedUser(), recipients, null);

	/*Properties props = new Properties();
	Session session = Session.getDefaultInstance(props, null);

	String htmlBody = "<br>" + getLoginedUser().getUserName() + " offers you this article: <a href='" + entry.getLink() + "'>" + entry.getTitle()
		+ "</a></br>";
	htmlBody += "<br>This message sent from the <a href='rscrssreader.appspot.com'>Rsc Rssfeeds</a> application</br>";

	try {
	    Message msg = new MimeMessage(session);
	    msg.setFrom(new InternetAddress(SENDER, APP_NAME));

	    for (String str : recipients) {
		msg.addRecipient(Message.RecipientType.TO, new InternetAddress(str, "Recipient"));
	    }

	    msg.setSubject(getLoginedUser().getUserName() + " offers you an article");

	    Multipart mp = new MimeMultipart();

	    MimeBodyPart htmlPart = new MimeBodyPart();
	    htmlPart.setContent(htmlBody, "text/html");
	    mp.addBodyPart(htmlPart);

	    msg.setContent(mp);

	    Transport.send(msg);

	} catch (Exception e) {
	    e.printStackTrace();
	}*/
    }

    private void autenticateGuest() {
	final HttpSession session = this.getThreadLocalRequest().getSession(true);
	String acceptLanguage = getThreadLocalRequest().getHeader("Accept-Language");
	String language = acceptLanguage != null && acceptLanguage.contains("hu") ? UserInfo.LANG_HU : UserInfo.LANG_EN;
	UserInfo userInfo = new UserInfo();
	userInfo.setId(1l);
	userInfo.setUserName("guest");
	userInfo.setEmail("");
	userInfo.setLang(language);
	userInfo.setRows(UserInfo.DEF_ROWS);
	userInfo.setCols(UserInfo.DEF_COLS);
	userInfo.setNeedmail(new Boolean(false));
	session.setAttribute("userInfo", userInfo);
    }

    private synchronized boolean checkChanelUrl(String url) throws Exception {
	try {
	    RssFeedParser rfp = new RssFeedParser(url, url);
	    rfp.getPostings();

	    return true;
	} catch (Exception e) {
	    e.printStackTrace();
	    return false;
	}

    }

    private void deleteAllUserFeeds() {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	final Query query = new Query(TABLE_USER_FEED);
	if (getLoginedUser() != null) {
	    query.addFilter(UserFeed.PROP_USER, Query.FilterOperator.EQUAL, getLoginedUser().getId());
	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable()) {
	    datastore.delete(e.getKey());
	}
    }

    private List<Feed> getFeeds(int sorting, boolean asc, int startRow, int numRows) {
	List<Feed> result = new ArrayList<Feed>();

	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_FEED);

	query.addFilter(Feed.PROP_OFFER_OFFERER, Query.FilterOperator.EQUAL, getLoginedUser().getId());

	switch (sorting) {
	case FieldMapping.FIELD_FEED_TITLE: {
	    query.addSort(Feed.PROP_LABEL, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_FEED_CATEGORY: {
	    query.addSort(Feed.PROP_CATEGORY, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_FEED_LANG: {
	    query.addSort(Feed.PROP_LANGUAGE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}

	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable(FetchOptions.Builder.withOffset(startRow).limit(numRows))) {
	    Feed f = new Feed();
	    f.setId(e.getKey().getId());
	    f.setCategory((Long) e.getProperty(Feed.PROP_CATEGORY));
	    f.setDescription((String) e.getProperty(Feed.PROP_DESCRIPTION));
	    f.setLabel((String) e.getProperty(Feed.PROP_LABEL));
	    f.setLanguage((String) e.getProperty(Feed.PROP_LANGUAGE));
	    f.setOfferer((Long) e.getProperty(Feed.PROP_OFFER_OFFERER));
	    f.setUrl((String) e.getProperty(Feed.PROP_URL));
	    result.add(f);
	}
	return result;
    }

    private HashMap<String, Feed> getFeedsPrivate(String key) {
	if (this.cache == null) {
	    try {
		CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
		this.cache = cacheFactory.createCache(Collections.emptyMap());
	    } catch (CacheException e) {
	    }
	}

	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	HashMap<String, Feed> result = new HashMap<String, Feed>();
	final Query query = new Query(TABLE_FEED);
	if (key != null) {
	    query.addFilter(Feed.PROP_LABEL, Query.FilterOperator.EQUAL, key);
	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity c : pq.asIterable()) {
	    Long id = c.getKey().getId();
	    String title = (String) c.getProperty(Feed.PROP_LABEL);
	    String url = (String) c.getProperty(Feed.PROP_URL);
	    Long category = (Long) c.getProperty(Feed.PROP_CATEGORY);
	    String language = (String) c.getProperty(Feed.PROP_LANGUAGE);
	    String description = (String) c.getProperty(Feed.PROP_DESCRIPTION);
	    Date offerDate = (Date) c.getProperty(Feed.PROP_OFFER_DATE);
	    /**
	     * If there are so Feed what has no offer date, set it and save.
	     */
	    if (offerDate == null) {
		c.setProperty(Feed.PROP_OFFER_DATE, new Date());
		datastore.put(c);
	    }
	    Feed feed = new Feed();
	    feed.setId(id);
	    feed.setLabel(title);
	    feed.setUrl(url);
	    feed.setCategory(category);
	    feed.setLanguage(language != null ? language : UserInfo.LANG_EN);
	    feed.setDescription(description);
	    result.put(title, feed);
	    this.cache.put(title, feed);
	}
	return result;
    }

    private List<GeneratedEntry> getGeneratedEntries(int sorting, boolean asc, ColumnFilterList filters, Long feed, int startRow, int numRows) {
	List<GeneratedEntry> result = new ArrayList<GeneratedEntry>();

	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_GENERATED_ENTRY);
	query.addFilter(GeneratedEntry.PROP_FEED, Query.FilterOperator.EQUAL, feed);

	Iterator<ColumnFilterInfo> iterator = filters.iterator();
	while (iterator.hasNext()) {
	    ColumnFilterInfo info = iterator.next();
	    if (info.getFilter() == null || info.getFilter().length() == 0) {
		continue;
	    }
	    switch (info.getColumn()) {
	    case FieldMapping.FIELD_ENTRY_DATE: {
		query.addFilter(GeneratedEntry.PROP_PUB_DATE, Query.FilterOperator.EQUAL, info.getFilter());
		break;
	    }
	    case FieldMapping.FIELD_ENTRY_TITLE: {
		query.addFilter(GeneratedEntry.PROP_TITLE, Query.FilterOperator.IN, info.getFilter());
		break;
	    }
	    }
	}

	switch (sorting) {
	case FieldMapping.FIELD_ENTRY_DATE: {
	    query.addSort(GeneratedEntry.PROP_PUB_DATE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_ENTRY_ID: {
	    query.addSort(GeneratedEntry.PROP_TITLE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_ENTRY_LINK: {
	    query.addSort(GeneratedEntry.PROP_LINK, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_ENTRY_TITLE: {
	    query.addSort(GeneratedEntry.PROP_TITLE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable(FetchOptions.Builder.withOffset(startRow).limit(numRows))) {
	    GeneratedEntry gf = new GeneratedEntry();
	    gf.setDescription(((Text) e.getProperty(GeneratedEntry.PROP_DESC)).getValue());
	    gf.setTitle((String) e.getProperty(GeneratedEntry.PROP_TITLE));
	    gf.setLink((String) e.getProperty(GeneratedEntry.PROP_LINK));
	    gf.setFeed((Long) e.getProperty(GeneratedEntry.PROP_FEED));
	    gf.setPubdate((Date) e.getProperty(GeneratedEntry.PROP_PUB_DATE));
	    gf.setId(e.getKey().getId());
	    result.add(gf);
	}
	return result;
    }

    private List<GeneratedFeed> getGeneratedFeeds(int sorting, boolean asc, int startRow, int numRows) {
	List<GeneratedFeed> result = new ArrayList<GeneratedFeed>();

	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_GENERATED_FEED);
	query.addFilter(GeneratedFeed.PROP_USERINFO, Query.FilterOperator.EQUAL, getLoginedUser().getId());

	switch (sorting) {
	case FieldMapping.FIELD_GEN_FEED_AUTHOR: {
	    query.addSort(GeneratedFeed.PROP_AUTHOR, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_GEN_FEED_ID: {
	    query.addSort(GeneratedFeed.PROP_PUB_DATE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_GEN_FEED_PUB_DATE: {
	    query.addSort(GeneratedFeed.PROP_PUB_DATE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_GEN_FEED_TITLE: {
	    query.addSort(GeneratedFeed.PROP_TITLE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable(FetchOptions.Builder.withOffset(startRow).limit(numRows))) {
	    GeneratedFeed gf = new GeneratedFeed();
	    gf.setAuthor((String) e.getProperty(GeneratedFeed.PROP_AUTHOR));
	    gf.setTitle((String) e.getProperty(GeneratedFeed.PROP_TITLE));
	    gf.setPubDate((Date) e.getProperty(GeneratedFeed.PROP_PUB_DATE));
	    gf.setId(e.getKey().getId());
	    result.add(gf);
	}
	return result;
    }

    private UserInfo getLoginedUser() {
	HttpSession session = this.getThreadLocalRequest().getSession(true);
	if (session.getAttribute("userInfo") == null) {
	    autenticateGuest();
	}
	return (UserInfo) session.getAttribute("userInfo");
    }

    private List<SystemFeed> getSystemFeeds(int sorting, boolean asc, int startRow, int numRows) {
	List<SystemFeed> result = new ArrayList<SystemFeed>();

	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_SYSTEM_FEED);
	query.addFilter(GeneratedFeed.PROP_USERINFO, Query.FilterOperator.EQUAL, getLoginedUser().getId());

	switch (sorting) {
	case FieldMapping.FIELD_SYSTEM_FEED_APPLICATION: {
	    query.addSort(SystemFeed.PROP_APPLICATION, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_SYSTEM_FEED_ISHELP: {
	    query.addSort(SystemFeed.PROP_ISHELP, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	case FieldMapping.FIELD_SYSTEM_FEED_LANGUAGE: {
	    query.addSort(SystemFeed.PROP_LANGUAGE, asc ? SortDirection.ASCENDING : SortDirection.DESCENDING);
	    break;
	}
	}

	PreparedQuery pq = datastore.prepare(query);
	for (Entity e : pq.asIterable(FetchOptions.Builder.withOffset(startRow).limit(numRows))) {
	    SystemFeed gf = new SystemFeed();
	    gf.setApplication((String) e.getProperty(SystemFeed.PROP_APPLICATION));
	    gf.setLanguage((String) e.getProperty(SystemFeed.PROP_LANGUAGE));
	    gf.setHelp((Boolean) e.getProperty(SystemFeed.PROP_ISHELP));
	    gf.setId(e.getKey().getId());
	    result.add(gf);
	}
	return result;
    }

    private List<UserCategory> getUserCategories() {
	List<UserCategory> categories = new ArrayList<UserCategory>();
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	if (getLoginedUser() == null || getLoginedUser().getId() == null) {
	    return categories;
	}

	final Query query = new Query(TABLE_USER_CATEGORY);
	query.addFilter(UserCategory.PROP_USER, Query.FilterOperator.EQUAL, getLoginedUser().getId());

	PreparedQuery pq = datastore.prepare(query);
	for (Entity c : pq.asIterable()) {
	    Long id = c.getKey().getId();
	    String title = (String) c.getProperty(UserCategory.PROP_LABEL);
	    Long user = (Long) c.getProperty(UserCategory.PROP_USER);
	    UserCategory cat = new UserCategory();
	    cat.setId(id);
	    cat.setLabel(title);
	    cat.setUser(user);
	    categories.add(cat);
	}
	return categories;
    }

    private void sendMailForNewFeed(GeneratedEntry entry, String lang) {
	final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	final Query query = new Query(TABLE_USER);
	query.addFilter(UserInfo.PROP_NEED_MAIL, Query.FilterOperator.EQUAL, new Boolean(true));
	query.addFilter(UserInfo.PROP_LANG, Query.FilterOperator.EQUAL, lang);

	List<String> recipients = new ArrayList<String>();
	PreparedQuery pq = datastore.prepare(query);
	for (Entity u : pq.asIterable()) {
	    recipients.add((String) u.getProperty(UserInfo.PROP_EMAIL));
	}
	if (!recipients.isEmpty()) {
	    new SendOfferMail(entry, getLoginedUser(), recipients, null);
	}
    }

}
